package bosVM2.meta;

public class LookUp {
	
	//Opcodes
	public enum opCode
	{ 
		//core
		NOP 	( 1), 		//0x00000001
		PUSH	( 2), 		//0x00000010
		POP		( 4), 		//0x00000100
		LOAD	( 7), 		//0x00000111
		STORE	( 8), 		//0x00001000
		GOTO	( 11),		//0x00001011
		IF		( 13),		//0x00001101
		ARIT	( 14),		//0x00001110
		//methods/functions
		INVOKEVIRTUAL ( 16),//0x00010000
		RETURN ( 19),		//0x00010011
		//Objects
		NEW	 ( 21),			//0x00010101
		GETFIELD ( 22),		//0x00010110
		PUTFIELD ( 25),     //0x00011001
		//Arrays - NYI
		//Exceptions
		THROW ( 32), 	    //0x00100000
		UNREC ( 255);
		
		
		public int opcode;
		
		private opCode(int opcode) {
			this.opcode = opcode;
		}
		public int getValue() { return opcode; }
		
		public static opCode getOpcode(int b)
		{ 
			switch(b)
			{
			case 1:	return NOP;
			case 2:	return PUSH;
			case 4:	return POP;
			case 7:	return LOAD;
			case 8: return STORE;
			case 11: return GOTO;
			case 13: return IF;
			case 14: return ARIT;
			case 16: return INVOKEVIRTUAL;
			case 19: return RETURN;
			case 21: return NEW;
			case 22: return GETFIELD;
			case 25: return PUTFIELD;
			default: return UNREC; //Add fault handling, Lookup is unrecognized int, get the proper int
			}
		}
	}

	//Opcodes enums by string
	public static opCode opCode(String op)
	{
		switch(op)
		{
			case "nop":   return opCode.NOP;
			case "push":  return opCode.PUSH;
			case "pop":   return opCode.POP;
			case "load":  return opCode.LOAD;
			case "store": return opCode.STORE;
			case "goto":  return opCode.GOTO;
			case "if":    return opCode.IF;
			case "arit":  return opCode.ARIT;
			case "invokevirtual" : return opCode.INVOKEVIRTUAL;
			case "return" : return opCode.RETURN;
			case "new": return opCode.NEW;
			case "getfield": return opCode.GETFIELD;
			case "putfield": return opCode.PUTFIELD;
			case "throw": return opCode.THROW;
			default: return null;
		}
	}
		
	//Arithmetic operations 
	public enum aritOp
	{
		ADD ( 1),
		SUB ( 2),
		MUL ( 4),
		DIV  ( 7),
		UNREC ( 255);
		
		private int b;
		private aritOp(int b)
		{
			this.b = b;
		}
		public int getValue(){ return b;}
		public static aritOp getArit(int b)
		{
			switch(b)
			{
				case 1: return ADD;
				case 2: return SUB;
				case 4: return MUL;
				case 7: return DIV;
				default: return UNREC; //Add fault handling, Lookup is unrecognized int, get the proper int
			}
		}
	}
	
	//aritOp by string
	public static aritOp aritOp(String op)
	{
		switch(op)
		{
			case "add": return aritOp.ADD;
			case "sub": return aritOp.SUB;
			case "mul": return aritOp.MUL;
			case "div": return aritOp.DIV;
			default: return null;
		}
	}
	
	 
	//if operations
	public enum ifOp
	{
		EQUALS  ( 1),
		NEQUALS ( 2),
		GRTH    ( 4),
		LSTH    ( 7),
		UNREC (255);
		
		private int b;
		private ifOp(int b)
		{ this.b = b;}
		public int getValue() { return b; }
		public static ifOp getIfOp(int b)
		{
			switch(b)
			{
			case 1: return EQUALS;
			case 2: return NEQUALS;
			case 4: return GRTH;
			case 7: return LSTH;
			default: return UNREC;
			}
		}
	}
	//if by string
	public static ifOp ifOp(String str)
	{
		switch(str)
		{
			case "equals": return  ifOp.EQUALS;
			case "nequals": return ifOp.NEQUALS;
			case "grth" : return ifOp.GRTH;
			case "lsth" : return ifOp.LSTH;
			default: return null;
		}
	}
	
	//Type lookup
	public enum Type
	{
		VOID ( 1),
		INT ( 2),
		BYTE ( 4),
		BOOLEAN ( 7), //0x00000000 -> false | 0x11111111 -> true
		REF ( 8),
		UNREC (255);
		
		private int b;
		private Type(int b)
		{ this.b = b; }
		public int getValue() {return b;}
		public static Type getTypeCode(int b)
		{
			switch(b)
			{
				case 1: return VOID;
				case 2: return INT;
				case 4: return BYTE;
				case 7: return BOOLEAN;
				case 8: return REF;
				default: return UNREC;
			}
		}
	}
	
	//type by string
	public static Type Type(String s)
	{
		switch(s)
		{
			case "void": return Type.VOID;
			case "int": return Type.INT;
			case "byte": return Type.INT;
			case "bool":return Type.BOOLEAN;
			case "ref": return Type.REF;
			default: return null;
		}
	}
	
	//retrieved the proper value of the typed field.
	public static Object getTypedValue(Type type, String value) throws Exception
	{
		switch(type) {
			case BOOLEAN: if(value.equals("true")) { return  255;} else { return  0;}
			case BYTE: return Integer.parseInt(value);
			case INT: return Integer.parseInt(value);
			case REF: return value;
			case VOID: throw new Exception(); //TODO change to proper exceptions
			default: throw new Exception(); //TODO change to proper exceptions
		
		}
	}
}
